﻿using System;
using System.Globalization;
using System.Linq;
using System.Collections.Generic;
using System.Reflection;
using System.Web.Mvc;
using Orchard;
using Orchard.ContentManagement;
using Orchard.Core.Contents;
using Orchard.Data;
using Orchard.DisplayManagement;
using Orchard.Localization;
using Orchard.Logging;
using Orchard.Themes;
using Orchard.Widgets.Services;

namespace NGM.Portlets.Controllers {
    [ValidateInput(false)]
    [Themed]
    public class ZoneController : Controller, IUpdateModel {
        private readonly IOrchardServices _orchardServices;
        private readonly IContentManager _contentManager;
        private readonly ITransactionManager _transactionManager;
        private readonly IWidgetsService _widgetsService;

        public ZoneController(
            IOrchardServices orchardServices,
            IContentManager contentManager,
            ITransactionManager transactionManager,
            IWidgetsService widgetsService,
            IShapeFactory shapeFactory) {
            _orchardServices = orchardServices;
            _contentManager = contentManager;
            _transactionManager = transactionManager;
            _widgetsService = widgetsService;
            T = NullLocalizer.Instance;
            Logger = NullLogger.Instance;
            Shape = shapeFactory;
        }

        dynamic Shape { get; set; }
        public Localizer T { get; set; }
        public ILogger Logger { get; set; }

        [HttpPatch]
        public ActionResult UpdatePositions(WidgetModel[] viewModel) {
                foreach (var widgetModel in viewModel) {
                var widget = _widgetsService.GetWidget(widgetModel.Id);

                widget.Zone = widgetModel.ZoneName;

                var ids = viewModel.Where(z => z.ZoneName == widget.Zone).Select(o => o.Id);

                int index = ids.TakeWhile(id => widget.Id != id).Count();

                widget.Position = index.ToString(CultureInfo.InvariantCulture);
            }

            return new HttpStatusCodeResult(200);
        }

        public ActionResult Manage(string zoneName) {
            var widgets = _widgetsService.GetWidgets();

            dynamic viewModel = Shape.ViewModel(Name: zoneName, Widgets: widgets);
                            //.Zone_Manage(Name: zoneName, Widgets: widgets);
            // Casting to avoid invalid (under medium trust) reflection over the protected View method and force a static invocation.
            return View((object)viewModel);
        }

        bool IUpdateModel.TryUpdateModel<TModel>(TModel model, string prefix, string[] includeProperties, string[] excludeProperties) {
            return TryUpdateModel(model, prefix, includeProperties, excludeProperties);
        }

        void IUpdateModel.AddModelError(string key, LocalizedString errorMessage) {
            ModelState.AddModelError(key, errorMessage.ToString());
        }
    }

    public class WidgetsViewModel {
        public List<WidgetModel> Widgets { get; set; }
    }

    public class WidgetModel {
        public int Id { get; set; }
        public string ZoneName { get; set; }
    }

    /// <summary>
    /// Represents an attribute that is used to restrict an action method so that the method handles only HTTP PATCH requests.
    /// </summary>
    public sealed class HttpPatchAttribute : ActionMethodSelectorAttribute {

        static readonly AcceptVerbsAttribute attr = new AcceptVerbsAttribute("PATCH");

        public override bool IsValidForRequest(ControllerContext controllerContext, MethodInfo methodInfo) {
            return attr.IsValidForRequest(controllerContext, methodInfo);
        }
    }
}